package com.adee.juc;

import com.adee.util.Utils;

import java.util.concurrent.locks.LockSupport;

/**
 * 参考：https://www.codetd.com/article/13769546
 *
 * LockSupport.park/unpark调用Unsafe.park/unpark，
 * jvm底层实现使用的是POSIX库标准的互斥量(锁)mutex和条件变量condition。
 *
 * 实际上JUC中的AQS框架的实现借鉴了底层系统的mutex和condition，
 * 如果我们理解了AQS的实现，那么理解mutex和condition的关系就很简单了。
 * 他们的区别就是AQS是采用Java语言实现的，而mutex和condition是系统工具，
 * 采用C++实现的。AQS中线程的阻塞park和唤醒unpark同样用到了mutex和condition的方法调用。
 *
 */
public class Test002_ParkUnPark {
    public static void main(String[] args) {
        //test1();
        test2();
    }


    /**
     * park挂起线程，unpark恢复线程，unpark可在park之前或之后调用，都有效
     * 每次调用unpark都往线程中会放一个许可，只要许可大于0，调用park的时候就会立即返回，并将许可数置0，
     * 因此，不管之前调用了多少次unpark，只要调用依次park，就会将许可置0。
     */
    public static void test1() {
        Thread t = new Thread(()->{
            Utils.sleep(3);
            LockSupport.park(); // jstack pid park()线程状态：WAITING (parking)
            LockSupport.park();
            System.out.println("线程恢复");
        });
        t.start();
        //Utils.sleep(3);
        LockSupport.unpark(t);
        LockSupport.unpark(t);
    }

    /**
     * park挂起线程，interrupt恢复线程
     * 只要线程调用了interrupt()方法，设置了中断标志，则该线程中所有的LockSupport.park()都会立即返回，
     * 跟许可数没关系，只要中断标志为true，就会立即返回。jvm源码中，Unsafe.park方法对应的c++源码有这样一段：
     *   //如果当前线程已经设置了中断标志，则park方法直接返回
     *   if (Thread::is_interrupted(thread, false)) {
     *     return;
     *   }
     *
     */

    public static void test2() {
        Thread t = new Thread(() -> {
            Thread.currentThread().interrupt();
            LockSupport.park();

            LockSupport.park();
            // System.out.println(Thread.interrupted()); // 返回当前中断标志，并重置中断标志位
            LockSupport.park();
            LockSupport.park();
            System.out.println("线程恢复");
        });
        t.start();
        Utils.sleep(1);
        //t.interrupt(); // 调用Thread的interrupt方法恢复线程
    }

    /**
     * LockSupport.unpark(t); 会重置线程的中断状态
     * 调用Thread.interrupted()也会重置终端标志位
     */
    public static void test3() {
        Thread t = new Thread(() -> {
            //Thread.currentThread().interrupt();
            LockSupport.park();

            LockSupport.park();
            Utils.sleep(3);
            LockSupport.park();
            LockSupport.park();
            System.out.println("线程恢复");
        });
        t.start();
        Utils.sleep(1);
        t.interrupt(); // 调用Thread的interrupt方法恢复线程
        LockSupport.unpark(t);
    }
}
